/*
Copyright 2008-2013 Josh Drummond
This file is part of WebPasswordSafe.
WebPasswordSafe is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
WebPasswordSafe is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with WebPasswordSafe; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.webpasswordsafe.server.dao;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.webpasswordsafe.common.model.AccessLevel;
import net.webpasswordsafe.common.model.Group;
import net.webpasswordsafe.common.model.Password;
import net.webpasswordsafe.common.model.Subject;
import net.webpasswordsafe.common.model.Tag;
import net.webpasswordsafe.common.model.User;
import net.webpasswordsafe.common.util.Constants.Function;
import net.webpasswordsafe.common.util.Constants.Match;
import net.webpasswordsafe.server.plugin.authorization.Authorizer;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.hibernate.impl.SessionFactoryImpl;
import org.hibernate.type.StandardBasicTypes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
* DAO implementation for Password
*
* @author Josh Drummond
*
*/
@Repository("passwordDAO")
public class PasswordDAOHibernate extends GenericHibernateDAO<Password, Long> implements PasswordDAO
{
@Autowired
private Authorizer authorizer;
@Override
@SuppressWarnings("unchecked")
public List<Password> findPasswordByFuzzySearch(String query, User user, boolean activeOnly, Collection<Tag> tags, Match tagMatch)
{
//kludge to not use ilike on text column if MSSQL
boolean isMSSQL = ((SessionFactoryImpl)getSessionFactory()).getDialect().toString().contains("SQLServer");
Criteria crit = getSession().createCriteria(getPersistentClass());
crit.setFetchMode("tags", FetchMode.JOIN);
crit.add(Restrictions.or(Restrictions.or(Restrictions.ilike("name", query, MatchMode.ANYWHERE),
Restrictions.ilike("username", query, MatchMode.ANYWHERE)), isMSSQL ?
Restrictions.like("notes", query, MatchMode.ANYWHERE) :
Restrictions.ilike("notes", query, MatchMode.ANYWHERE)));
if (activeOnly)
{
crit.add(Restrictions.eq("active", true));
}
Criterion tagsCriterion = null;
for (Tag tag : tags)
{
Criterion tc = Restrictions.sqlRestriction("? in (select tag_id from password_tags where password_id = {alias}.id)", tag.getId(), StandardBasicTypes.LONG);
if (null == tagsCriterion)
{
tagsCriterion = tc;
}
else
{
tagsCriterion = tagMatch.equals(Match.AND) ? Restrictions.and(tagsCriterion, tc) : Restrictions.or(tagsCriterion, tc);
}
}
if (tagsCriterion != null) crit.add(tagsCriterion);
crit.createAlias("permissions", "pm");
crit.add(Restrictions.in("pm.accessLevel",
new String[] {AccessLevel.READ.name(), AccessLevel.WRITE.name(), AccessLevel.GRANT.name()}));
if (!authorizer.isAuthorized(user, Function.BYPASS_PASSWORD_PERMISSIONS.name()))
{
DetachedCriteria groupQuery = DetachedCriteria.forClass(Group.class);
groupQuery.setProjection(Projections.id());
groupQuery.createCriteria("users", "u").add(Restrictions.eq("u.id", user.getId()));
crit.add(Restrictions.or(Restrictions.eq("pm.subject", user), Subqueries.propertyIn("pm.subject", groupQuery)));
}
crit.addOrder(Order.asc("name"));
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return crit.list();
}
@Override
@SuppressWarnings("unchecked")
public Password findAllowedPasswordById(long passwordId, User user, AccessLevel accessLevel)
{
Password foundPassword = null;
String sqlAccessLevelIn = null;
switch (accessLevel) {
case GRANT : sqlAccessLevelIn = "(:aclgrant) "; break;
case WRITE : sqlAccessLevelIn = "(:aclwrite, :aclgrant) "; break;
case READ : sqlAccessLevelIn = "(:aclread, :aclwrite, :aclgrant) "; break;
}
StringBuilder hqlString = new StringBuilder();
hqlString.append("select distinct pw.id from Password pw join pw.permissions pm where pw.id = :passwordId ");
if (!authorizer.isAuthorized(user, Function.BYPASS_PASSWORD_PERMISSIONS.name()))
{
hqlString.append(" and pm.accessLevel in ");
hqlString.append(sqlAccessLevelIn);
hqlString.append("and ((pm.subject = :user) or (pm.subject in (select g from Group g join g.users u where u = :user)))");
}
Query hqlQuery = getSession().createQuery(hqlString.toString());
hqlQuery.setLong("passwordId", passwordId);
if (!authorizer.isAuthorized(user, Function.BYPASS_PASSWORD_PERMISSIONS.name()))
{
hqlQuery.setEntity("user", user);
if (accessLevel.equals(AccessLevel.GRANT) || accessLevel.equals(AccessLevel.WRITE) || accessLevel.equals(AccessLevel.READ))
{
hqlQuery.setString("aclgrant", AccessLevel.GRANT.name());
}
if (accessLevel.equals(AccessLevel.WRITE) || accessLevel.equals(AccessLevel.READ))
{
hqlQuery.setString("aclwrite", AccessLevel.WRITE.name());
}
if (accessLevel.equals(AccessLevel.READ))
{
hqlQuery.setString("aclread", AccessLevel.READ.name());
}
}
List<Long> passwordIds = hqlQuery.list();
if (passwordIds.size() > 0)
{
foundPassword = findById(passwordIds.get(0));
foundPassword.getPermissions().size();
foundPassword.getTags().size();
}
return foundPassword;
}
@Override
@SuppressWarnings("unchecked")
public AccessLevel getMaxEffectiveAccessLevel(Password password, User user)
{
AccessLevel maxEffectiveAccessLevel = null;
if (authorizer.isAuthorized(user, Function.BYPASS_PASSWORD_PERMISSIONS.name()))
{
maxEffectiveAccessLevel = AccessLevel.GRANT;
}
else
{
StringBuilder hqlString = new StringBuilder();
hqlString.append("select distinct pm.accessLevel from Permission pm ");
hqlString.append("where pm.password = :password ");
hqlString.append("and pm.accessLevel in (:aclread, :aclwrite, :aclgrant) ");
hqlString.append("and ((pm.subject = :user) or (pm.subject in (select g from Group g join g.users u where u = :user)))");
Query hqlQuery = getSession().createQuery(hqlString.toString());
hqlQuery.setEntity("password", password);
hqlQuery.setEntity("user", user);
hqlQuery.setString("aclread", AccessLevel.READ.name());
hqlQuery.setString("aclwrite", AccessLevel.WRITE.name());
hqlQuery.setString("aclgrant", AccessLevel.GRANT.name());
Set<String> accessLevels = new HashSet<String>(hqlQuery.list());
if (accessLevels.contains(AccessLevel.GRANT.name()))
{
maxEffectiveAccessLevel = AccessLevel.GRANT;
}
else if (accessLevels.contains(AccessLevel.WRITE.name()))
{
maxEffectiveAccessLevel = AccessLevel.WRITE;
}
else if (accessLevels.contains(AccessLevel.READ.name()))
{
maxEffectiveAccessLevel = AccessLevel.READ;
}
}
return maxEffectiveAccessLevel;
}
@Override
public Password findPasswordByName(String passwordName, String username)
{
List<Password> passwords = findByCriteria(Restrictions.and(Restrictions.eq("name", passwordName), Restrictions.eq("username", username)));
return (passwords.size() > 0) ? passwords.get(0) : null;
}
@Override
@SuppressWarnings("unchecked")
public List<Password> findPasswordsByPermissionSubject(Subject subject)
{
Query hqlQuery = getSession().createQuery("select distinct p from Password p join p.permissions pm where pm.subject = :subject");
hqlQuery.setEntity("subject", subject);
return hqlQuery.list();
}
}